// 
#pragma once
#ifndef __HWINDATETIME_H__
#define __HWINDATETIME_H__

#include "hwindef.h"
#include "hwinlog.h"


namespace harlinn
{
    namespace windows
    {
        namespace globalization
        {
            class Calendar;
        };

        enum class DateTimeKind
        {
            Unspecified = 0,
            Utc = 1,
            Local = 2
        };

        enum class DayOfWeek
        {
            Sunday = 0,
            Monday = 1,
            Tuesday = 2,
            Wednesday = 3,
            Thursday = 4,
            Friday = 5,
            Saturday = 6
        };

        enum class DatePart
        {
            Year = 0, 
            DayOfYear = 1,
            Month = 2,
            Day = 3
        };

        
        class DateTime;
        class TimeSpan
        {
            friend class DateTime;
        public:
            static const long long TicksPerMillisecond =  10000; 
            static const long long TicksPerSecond = TicksPerMillisecond * 1000; 
            static const long long TicksPerMinute = TicksPerSecond * 60;
            static const long long TicksPerHour = TicksPerMinute * 60; 
            static const long long TicksPerDay = TicksPerHour * 24; 
 
            HWIN_EXPORT static const TimeSpan Zero;
            HWIN_EXPORT static const TimeSpan MaxValue; 
            HWIN_EXPORT static const TimeSpan MinValue;

        private:
            
 
            static const int MillisPerSecond = 1000;
            static const int MillisPerMinute = MillisPerSecond * 60;
            static const int MillisPerHour = MillisPerMinute * 60;
            static const int MillisPerDay = MillisPerHour * 24; 

            
            static const long long MaxSeconds = MAXINT64 / TicksPerSecond; 
            static const long long MinSeconds = MININT64 / TicksPerSecond; 

            static const long long MaxMilliSeconds = MAXINT64 / TicksPerMillisecond; 
            static const long long MinMilliSeconds = MININT64 / TicksPerMillisecond;

            static const long long TicksPerTenthSecond = TicksPerMillisecond * 100;

            long long ticks;

            HWIN_EXPORT static TimeSpan Interval(double theValue, int theScale); 
        public:
            HWIN_EXPORT static long long TimeToTicks(int theDays, int theHours = 0, int theMinutes = 0, int theSeconds = 0, int theMilliseconds = 0);

            TimeSpan() : ticks(0) 
            {
                HWIN_TRACE();
            }

            explicit TimeSpan(long long theTicks) 
                : ticks(theTicks) 
            {
                HWIN_TRACE();
            }

            TimeSpan(const TimeSpan& other) 
                : ticks(other.ticks) 
            {
                HWIN_TRACE();
            }

            TimeSpan(int hours, int minutes, int seconds) 
                : ticks(TimeToTicks(0,hours, minutes, seconds)) 
            {
                HWIN_TRACE();
            }

            TimeSpan(int days, int hours, int minutes, int seconds) 
                : ticks(TimeToTicks(days,hours, minutes, seconds)) 
            {
                HWIN_TRACE();
            }
 
            TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds) 
                : ticks(TimeToTicks(days,hours, minutes, seconds,milliseconds)) 
            {
                HWIN_TRACE();
            }

            long long Ticks() const
            {   
                HWIN_TRACE();
                return ticks;
            }
 
            int Days() const
            {
                HWIN_TRACE();
                return (int)(ticks / TicksPerDay); 
            }
 
            int Hours() const
            { 
                HWIN_TRACE();
                return (int)((ticks / TicksPerHour) % 24);  
            } 

            int Milliseconds() const
            { 
                HWIN_TRACE();
                return (int)((ticks / TicksPerMillisecond) % 1000); 
            }

            int Minutes() const
            { 
                HWIN_TRACE();
                return (int)((ticks / TicksPerMinute) % 60); 
            } 
 
            int Seconds() const
            { 
                HWIN_TRACE();
                return (int)((ticks / TicksPerSecond) % 60); 
            }

            HWIN_EXPORT double TotalDays() const;
 
            HWIN_EXPORT double TotalHours() const;

            HWIN_EXPORT double TotalMilliseconds() const;
             

            HWIN_EXPORT double TotalMinutes() const;
 
            HWIN_EXPORT double TotalSeconds() const;
 
            HWIN_EXPORT TimeSpan Add(const TimeSpan& other) const; 

            static int Compare(const TimeSpan& t1, const TimeSpan& t2) 
            { 
                HWIN_TRACE();
                if (t1.ticks > t2.ticks) 
                {
                    return 1;
                }
                if (t1.ticks < t2.ticks) 
                {
                    return -1; 
                }
                return 0; 
            }
 
            int CompareTo(const TimeSpan& value) const
            { 
                HWIN_TRACE();
                if (ticks > value.ticks) 
                {
                    return 1; 
                }
                if (ticks < value.ticks) 
                {
                    return -1; 
                }
                return 0;
            } 

            static TimeSpan FromDays(double value) 
            {
                HWIN_TRACE();
                return Interval(value, MillisPerDay); 
            }
 
            HWIN_EXPORT TimeSpan Duration() const;
 
            int HashCode() const
            {
                HWIN_TRACE();
                return (int)ticks ^ (int)(ticks >> 32); 
            }
 
            static TimeSpan FromHours(double value) 
            { 
                HWIN_TRACE();
                return Interval(value, MillisPerHour);
            } 

            static TimeSpan FromMilliseconds(double value) 
            { 
                HWIN_TRACE();
                return Interval(value, 1);
            } 
 
            static TimeSpan FromMinutes(double value) 
            {
                HWIN_TRACE();
                return Interval(value, MillisPerMinute); 
            }

            HWIN_EXPORT TimeSpan Negate() const;
 
            static TimeSpan FromSeconds(double value)
            {
                HWIN_TRACE();
                return Interval(value, MillisPerSecond);
            }
 
            HWIN_EXPORT TimeSpan Subtract(const TimeSpan& theOther) const; 
    
            static TimeSpan FromTicks(long long value) 
            { 
                HWIN_TRACE();
                return TimeSpan(value);
            }

            TimeSpan operator + (const TimeSpan& theValue) const
            {
                HWIN_TRACE();
                return Add(theValue);
            }

            TimeSpan operator - (const TimeSpan& theValue) const
            {
                return Subtract(theValue);
            }

            bool operator == (const TimeSpan& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) == 0; 
            }
            bool operator != (const TimeSpan& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) != 0; 
            }
            bool operator <  (const TimeSpan& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) <  0; 
            }
            bool operator <= (const TimeSpan& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) <= 0; 
            }
            bool operator >  (const TimeSpan& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) >  0; 
            }
            bool operator >= (const TimeSpan& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) >= 0; 
            }

            HWIN_EXPORT String ToString() const;


        };




        class DateTime 
        { 
 
            unsigned long long data;

            HWIN_EXPORT explicit DateTime(unsigned long long dateData);

            HWIN_EXPORT static long long ToTicks(int year, int month, int day, const globalization::Calendar& calendar); 
            HWIN_EXPORT static long long ToTicks(int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar); 
            HWIN_EXPORT static bool TryCreate(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTime& result);
        public:
            HWIN_EXPORT static const DateTime MinValue;
            HWIN_EXPORT static const DateTime MaxValue;

            HWIN_EXPORT static long long DateToTicks(int year, int month, int day); 
            HWIN_EXPORT static long long TimeToTicks(int hour, int minute, int second);
            HWIN_EXPORT static long long SystemTimeToTicks(const SYSTEMTIME& systemTime);

            HWIN_EXPORT explicit DateTime(long long ticks);
            HWIN_EXPORT DateTime(long long ticks, DateTimeKind kind);

            HWIN_EXPORT DateTime(int year, int month, int day);
            HWIN_EXPORT DateTime(int year, int month, int day, const globalization::Calendar& calendar);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second, const globalization::Calendar& calendar);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar);
            HWIN_EXPORT DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar, DateTimeKind kind);
 
            HWIN_EXPORT DateTime Add(const TimeSpan& value) const; 
            HWIN_EXPORT DateTime Add(double value, int scale) const; 
            HWIN_EXPORT DateTime AddDays(double value) const; 
            HWIN_EXPORT DateTime AddHours(double value) const; 
            HWIN_EXPORT DateTime AddMilliseconds(double value) const; 
            HWIN_EXPORT DateTime AddMinutes(double value) const; 
            HWIN_EXPORT DateTime AddMonths(int months) const; 
            HWIN_EXPORT DateTime AddSeconds(double value) const; 
            HWIN_EXPORT DateTime AddTicks(long long value) const; 
            HWIN_EXPORT DateTime AddYears(int value) const; 

            HWIN_EXPORT const DateTime& AssingTo(SYSTEMTIME& systemTime) const; 

            HWIN_EXPORT std::string DateToAnsiString() const;
            HWIN_EXPORT String DateToString() const;

            HWIN_EXPORT std::string TimeToAnsiString() const;
            HWIN_EXPORT String TimeToString() const;

            HWIN_EXPORT std::string ToAnsiString() const;
            HWIN_EXPORT String ToString() const;

            HWIN_EXPORT TimeSpan Subtract(const DateTime& value) const;
            HWIN_EXPORT DateTime Subtract(const TimeSpan& value) const;

            HWIN_EXPORT static int Compare(const DateTime& t1, const DateTime& t2); 
            HWIN_EXPORT int CompareTo(const DateTime& value) const; 
        
            bool operator == (const DateTime& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) == 0; 
            }
            bool operator != (const DateTime& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) != 0; 
            }
            bool operator <  (const DateTime& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) <  0; 
            }
            bool operator <= (const DateTime& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) <= 0; 
            }
            bool operator >  (const DateTime& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) >  0; 
            }
            bool operator >= (const DateTime& other) const 
            { 
                HWIN_TRACE();
                return CompareTo(other) >= 0; 
            }

            DateTime operator + (const TimeSpan& theValue) const
            {
                HWIN_TRACE();
                return Add(theValue);
            }

            DateTime operator - (const TimeSpan& theValue) const
            {
                HWIN_TRACE();
                return Subtract(theValue);
            }

            TimeSpan operator - (const DateTime& theValue) const
            {
                HWIN_TRACE();
                return Subtract(theValue);
            }

        
            HWIN_EXPORT static int DaysInMonth(int year, int month); 
        
            HWIN_EXPORT static long long DoubleDateToTicks(double value);

            HWIN_EXPORT static DateTime FromBinary(long long dateData);
            HWIN_EXPORT static DateTime FromFileTime(long long fileTime);
            HWIN_EXPORT static DateTime FromFileTimeUtc(long long fileTime);

            HWIN_EXPORT static DateTime FromOADate(double d);
            HWIN_EXPORT bool IsDaylightSavingTime() const;

            HWIN_EXPORT static DateTime SpecifyKind(const DateTime& value, DateTimeKind kind);

            HWIN_EXPORT long long ToBinary() const;

            HWIN_EXPORT int GetDatePart(DatePart datePart) const;

            HWIN_EXPORT DateTime Date() const;

            HWIN_EXPORT int Year() const;
            HWIN_EXPORT int Month() const;
            HWIN_EXPORT int Day() const;
            HWIN_EXPORT int DayOfMonth() const;
            HWIN_EXPORT DayOfWeek DayOfWeek() const;
            HWIN_EXPORT int DayOfYear() const;
            
            HWIN_EXPORT int Hour() const;

            
            HWIN_EXPORT int Minute() const;
            HWIN_EXPORT int Second() const;
            HWIN_EXPORT int Millisecond() const;
            HWIN_EXPORT long long Ticks() const;

            HWIN_EXPORT TimeSpan TimeOfDay() const;

            HWIN_EXPORT DateTimeKind Kind() const;
            
            HWIN_EXPORT static DateTime Now();
            HWIN_EXPORT static DateTime UtcNow();
            HWIN_EXPORT static DateTime Today();

            HWIN_EXPORT static bool IsLeapYear(int year);

            HWIN_EXPORT static double TicksToOADate(long long value);
 
            HWIN_EXPORT double ToOADate() const;
 
            HWIN_EXPORT long long ToFileTime() const;
 
            HWIN_EXPORT long long ToFileTimeUtc() const;

            HWIN_EXPORT DateTime ToLocalTime() const;
 
            HWIN_EXPORT DateTime ToUniversalTime() const;
            
        };

        class Stopwatch 
        { 
            long long elapsedTicks;
            long long startedAt;
            bool isRunning;
 
            static long long frequency; 
        public:
            
            HWIN_EXPORT static const bool IsHighResolution;
        private: 
            static double tickFrequency; 
            static bool InitializeStopwatch(); 

            long long GetElapsedDateTimeTicks() const;

        public:
            HWIN_EXPORT static long long GetTimestamp();
            HWIN_EXPORT static double GetTimestampInSeconds();
            HWIN_EXPORT static double GetTimestampInMilliseconds();
            HWIN_EXPORT static long long Frequency();
            HWIN_EXPORT Stopwatch();
            HWIN_EXPORT void Start();
            HWIN_EXPORT Stopwatch StartNew();

            HWIN_EXPORT void Stop();
            HWIN_EXPORT void Reset();
            HWIN_EXPORT void Restart(); 
            HWIN_EXPORT bool IsRunning() const;
 
            HWIN_EXPORT TimeSpan Elapsed() const;
            HWIN_EXPORT long long ElapsedMilliseconds() const;
            HWIN_EXPORT long long ElapsedTicks() const;
        };


    };
};



#endif //__HWINDATETIME_H__